package com.intellif.mozping.concurrentutil.completionServicep;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author by mozping
 * @Classname CompletionServiceTest
 * @Description CompletionService工具类测试
 * 任务类是：随机睡眠一段时间来模拟执行任务的耗时，睡眠时间小于1000ms
 * 情况1是普通情况，将任务提交到线程池之后，按照提交任务的顺序依次去除对应任务的结果，最后检查整个过程sleep的时间和总耗时
 * 情况2是使用CompletionService，它不会按照提交任务的顺序去获取结果，而是先获取那些先完成的，在获取后完成的，因此总的耗时
 * 会很接近最慢的那个任务的消耗时间
 * 测试的结果发现使用CompletionService会快一些，而且总耗时比较接近最慢的任务的耗时
 * @Date 2019/6/20 17:48
 */
public class CompletionServiceTest {

    private final int POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private final int TOTAL_TASK = Runtime.getRuntime().availableProcessors();

    /**
     * 方法一，自己写集合来实现获取线程池中任务的返回结果
     */
    private void testByQueue() throws Exception {
        long start = System.currentTimeMillis();
        //统计所有任务休眠的总时长
        AtomicInteger count = new AtomicInteger(0);
        //1.创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        //2.容器存放提交给线程池的任务的结果
        BlockingQueue<Future<Integer>> queue = new LinkedBlockingQueue<Future<Integer>>();

        //3.提交任务
        for (int i = 0; i < TOTAL_TASK; i++) {
            Future<Integer> future = pool.submit(new WorkTask("ExecTask" + i));
            //将结果的Future对象放到队列
            queue.add(future);
        }

        //4.按照提交的顺序，依次阻塞式获取结果
        for (int i = 0; i < TOTAL_TASK; i++) {
            int sleptTime = queue.take().get();
            //打印具体任务的耗时
            System.out.println("Task sleep " + sleptTime + " ms ...");
            count.addAndGet(sleptTime);
        }

        //5.关闭线程池,打印结果
        pool.shutdown();
        System.out.println("Without CompletionService: tasks sleep total  time " + count.get()
                + "ms, and get result spend time is : " + (System.currentTimeMillis() - start) + " ms");
    }

    /**
     * 方法二，通过CompletionService来实现获取线程池中任务的返回结果
     */
    private void testByCompletion() throws Exception {
        long start = System.currentTimeMillis();
        AtomicInteger count = new AtomicInteger(0);
        //1.创建线程池
        ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
        //2.使用CompletionService获取任务的结果
        CompletionService<Integer> cService = new ExecutorCompletionService<>(pool);

        //3.通过CompletionService提交任务
        for (int i = 0; i < TOTAL_TASK; i++) {
            cService.submit(new WorkTask("ExecTask" + i));
        }

        //4.通过CompletionService获取结果
        for (int i = 0; i < TOTAL_TASK; i++) {
            int sleptTime = cService.take().get();
            //打印具体任务的耗时
            System.out.println("Task sleep " + sleptTime + " ms ...");
            count.addAndGet(sleptTime);
        }

        //5.关闭线程池,打印结果
        pool.shutdown();
        System.out.println("CompletionService tasks sleep time " + count.get()
                + "ms,and spend time " + (System.currentTimeMillis() - start) + " ms");
    }

    public static void main(String[] args) throws Exception {
        CompletionServiceTest t = new CompletionServiceTest();
        t.testByQueue();
        t.testByCompletion();
    }
}